package websocket

import (
	"encoding/json"
	"log"
	"sync"
	"time"

	"miracle-recorder/internal/models"

	"github.com/gorilla/websocket"
)

type Client struct {
	ID       string
	UserID   string
	TopicID  string
	Conn     *websocket.Conn
	Send     chan []byte
}

type Hub struct {
	Clients    map[string]*Client
	Register   chan *Client
	Unregister chan *Client
	Broadcast  chan []byte
	mutex      sync.RWMutex
}

type Manager struct {
	Hubs map[string]*Hub
	mutex sync.RWMutex
}

func NewManager() *Manager {
	return &Manager{
		Hubs: make(map[string]*Hub),
	}
}

func (m *Manager) HandleConnection(w http.ResponseWriter, r *http.Request, userID, topicID string) {
	upgrader := websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin: func(r *http.Request) bool {
			return true // 在生产环境中应该验证origin
		},
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Printf("Failed to upgrade connection: %v", err)
		return
	}

	// 为每个话题创建hub
	hubKey := topicID
	m.mutex.Lock()
	hub, exists := m.Hubs[hubKey]
	if !exists {
		hub = &Hub{
			Clients:    make(map[string]*Client),
			Register:   make(chan *Client),
			Unregister: make(chan *Client),
			Broadcast:  make(chan []byte),
		}
		go hub.Run()
		m.Hubs[hubKey] = hub
	}
	m.mutex.Unlock()

	// 创建客户端
	client := &Client{
		ID:      generateClientID(),
		UserID:  userID,
		TopicID: topicID,
		Conn:    conn,
		Send:    make(chan []byte, 256),
	}

	// 注册客户端
	hub.Register <- client

	// 启动读写协程
	go client.WritePump()
	go client.ReadPump(hub)
}

func (m *Manager) BroadcastToTopic(topicID string, message interface{}) error {
	m.mutex.RLock()
	hub, exists := m.Hubs[topicID]
	m.mutex.RUnlock()

	if !exists {
		return fmt.Errorf("topic hub not found")
	}

	data, err := json.Marshal(message)
	if err != nil {
		return fmt.Errorf("failed to marshal message: %w", err)
	}

	hub.Broadcast <- data
	return nil
}

func (h *Hub) Run() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case client := <-h.Register:
			h.mutex.Lock()
			h.Clients[client.ID] = client
			h.mutex.Unlock()

			// 发送欢迎消息
			welcomeMsg := map[string]interface{}{
				"type":    "welcome",
				"message": "Welcome to the topic",
				"client_id": client.ID,
			}
			welcomeData, _ := json.Marshal(welcomeMsg)
			client.Send <- welcomeData

			// 通知其他客户端
			joinMsg := map[string]interface{}{
				"type":      "user_joined",
				"user_id":   client.UserID,
				"client_id": client.ID,
				"timestamp": time.Now().Unix(),
			}
			joinData, _ := json.Marshal(joinMsg)
			h.broadcastToOthers(client.ID, joinData)

		case client := <-h.Unregister:
			h.mutex.Lock()
			if _, ok := h.Clients[client.ID]; ok {
				delete(h.Clients, client.ID)
				close(client.Send)
			}
			h.mutex.Unlock()

			// 通知其他客户端
			leaveMsg := map[string]interface{}{
				"type":      "user_left",
				"user_id":   client.UserID,
				"client_id": client.ID,
				"timestamp": time.Now().Unix(),
			}
			leaveData, _ := json.Marshal(leaveMsg)
			h.broadcastToOthers(client.ID, leaveData)

		case message := <-h.Broadcast:
			h.mutex.RLock()
			for _, client := range h.Clients {
				select {
				case client.Send <- message:
				default:
					close(client.Send)
					h.mutex.RUnlock()
					h.mutex.Lock()
					delete(h.Clients, client.ID)
					h.mutex.Unlock()
					h.mutex.RLock()
				}
			}
			h.mutex.RUnlock()

		case <-ticker.C:
			// 发送心跳
			h.mutex.RLock()
			for _, client := range h.Clients {
				heartbeat := map[string]interface{}{
					"type":      "heartbeat",
					"timestamp": time.Now().Unix(),
				}
				heartbeatData, _ := json.Marshal(heartbeat)
				select {
				case client.Send <- heartbeatData:
				default:
					close(client.Send)
					h.mutex.RUnlock()
					h.mutex.Lock()
					delete(h.Clients, client.ID)
					h.mutex.Unlock()
					h.mutex.RLock()
				}
			}
			h.mutex.RUnlock()
		}
	}
}

func (h *Hub) broadcastToOthers(clientID string, data []byte) {
	h.mutex.RLock()
	for id, client := range h.Clients {
		if id != clientID {
			select {
			case client.Send <- data:
			default:
				close(client.Send)
				h.mutex.RUnlock()
				h.mutex.Lock()
				delete(h.Clients, id)
				h.mutex.Unlock()
				h.mutex.RLock()
			}
		}
	}
	h.mutex.RUnlock()
}

func (c *Client) ReadPump(hub *Hub) {
	defer func() {
		hub.Unregister <- c
		c.Conn.Close()
	}()

	c.Conn.SetReadLimit(512 * 1024) // 512KB
	c.Conn.SetReadDeadline(time.Now().Add(30 * time.Second))
	c.Conn.SetPongHandler(func(string) error {
		c.Conn.SetReadDeadline(time.Now().Add(30 * time.Second))
		return nil
	})

	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("Error reading message: %v", err)
			}
			break
		}

		// 处理消息
		var msg map[string]interface{}
		if err := json.Unmarshal(message, &msg); err != nil {
			log.Printf("Failed to unmarshal message: %v", err)
			continue
		}

		// 添加客户端信息
		msg["client_id"] = c.ID
		msg["user_id"] = c.UserID
		msg["topic_id"] = c.TopicID
		msg["timestamp"] = time.Now().Unix()

		// 转发消息到其他客户端
		response, _ := json.Marshal(msg)
		hub.broadcastToOthers(c.ID, response)
	}
}

func (c *Client) WritePump() {
	ticker := time.NewTicker(15 * time.Second)
	defer func() {
		ticker.Stop()
		c.Conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.Send:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if !ok {
				c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			if err := c.Conn.WriteMessage(websocket.TextMessage, message); err != nil {
				log.Printf("Error writing message: %v", err)
				return
			}

		case <-ticker.C:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				log.Printf("Error writing ping: %v", err)
				return
			}
		}
	}
}

func generateClientID() string {
	return uuid.New().String()
}

// 消息类型常量
const (
	MessageTypeText       = "text"
	MessageTypeImage      = "image"
	MessageTypeVideo      = "video"
	MessageTypeFile       = "file"
	MessageTypeEmoji      = "emoji"
	MessageTypingStart    = "typing_start"
	MessageTypingStop     = "typing_stop"
	MessageReaction       = "reaction"
	MessageSystem         = "system"
	MessageHeartbeat      = "heartbeat"
)

// 消息结构
type WebSocketMessage struct {
	Type      string      `json:"type"`
	Content   string      `json:"content,omitempty"`
	MediaURL  string      `json:"media_url,omitempty"`
	MediaType string      `json:"media_type,omitempty"`
	Reaction  string      `json:"reaction,omitempty"`
	UserID    string      `json:"user_id"`
	ClientID  string      `json:"client_id"`
	TopicID   string      `json:"topic_id"`
	Data      interface{} `json:"data,omitempty"`
	Timestamp int64       `json:"timestamp"`
}

// 创建交互消息
func CreateInteractionMessage(interaction *models.Interaction) *WebSocketMessage {
	return &WebSocketMessage{
		Type:      interaction.Type,
		Content:   interaction.Content,
		MediaURL:  interaction.MediaURL,
		MediaType: interaction.MediaType,
		UserID:    strconv.Itoa(interaction.UserID),
		TopicID:   strconv.Itoa(interaction.TopicID),
		Timestamp: interaction.CreatedAt.Unix(),
		Data: map[string]interface{}{
			"interaction_id": interaction.ID,
			"like_count":     interaction.LikeCount,
			"reply_count":    interaction.ReplyCount,
		},
	}
}

// 创建系统消息
func CreateSystemMessage(topicID, message string) *WebSocketMessage {
	return &WebSocketMessage{
		Type:      MessageSystem,
		Content:   message,
		TopicID:   topicID,
		Timestamp: time.Now().Unix(),
	}
}

// 创建反应消息
func CreateReactionMessage(topicID, userID, reaction string, targetID int) *WebSocketMessage {
	return &WebSocketMessage{
		Type:      MessageReaction,
		Reaction:  reaction,
		UserID:    userID,
		TopicID:   topicID,
		Timestamp: time.Now().Unix(),
		Data: map[string]interface{}{
			"target_id": targetID,
		},
	}
}